/**
 * Created by qunxing.du on 2016/7/26.
 * Copyright 2016 汉威.智慧环保事业部 Limited.
 * All rights reserved.
 */
package com.hw.one.collect.zzcity;

import com.hw.one.collect.client.ChannelInitinalizerFactory;
import com.hw.one.collect.client.HttpClient;
import com.hw.one.collect.util.HashUtil;
import com.hw.one.collect.util.ParamsUtil;
import com.hw.one.collect.zzcity.constants.ZzCityConstants;
import com.hw.one.collect.zzcity.memento.ZzCityCareTaker;
import com.hw.one.collect.zzcity.memento.ZzCityMemento;
import com.hw.one.collect.zzcity.memento.ZzCityOriginator;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;

import java.net.URI;
import java.util.Iterator;
import java.util.Map;

/**
 *  郑州市客户端
 */
public class ZzCityClient extends HttpClient{
    protected static Logger log = Logger.getLogger(ZzCityClient.class);


    public synchronized void execute(Map<String, String> map) throws Exception {
        //封装参数
        String params = wrapParams(map);
        //添加备忘录
        createMemento(params);
        //获取通道
        ChannelInitializer channelInitializer = getChannelInitializer(ZzCityConstants.HOST,ZzCityConstants.PORT,ZzCityConstants.URI,params);
        //连接请求
        connect(ZzCityConstants.HOST,ZzCityConstants.PORT,ZzCityConstants.URI,params,channelInitializer);
    }
    /**
     * 封装参数
     */
    private String wrapParams(Map<String,String> map) throws Exception{
        String params = "apikey="+ ZzCityConstants.APIKEY+"&pCode="+ZzCityConstants.PCODE;

        if(map != null){
            //如果uCode不存在，则使用全部uCode
            if(map.get("uCode") == null){
                params += "&uCode="+ZzCityConstants.UCODE;
                map.remove("uCode");
            }else{
                String uCode = map.get("uCode");
                map.remove("uCode");
                params += "&uCode="+uCode;
            }
            //处理除uCode外其他参数
            String dynamicParams = "";
            Iterator<String> iterator = map.keySet().iterator();
            while (iterator.hasNext()){
                String key = iterator.next();
                String value = map.get(key);
                dynamicParams += "&"+key+"="+value;
            }
            log.debug("传递参数："+dynamicParams);
            if(StringUtils.isNotBlank(dynamicParams)){
                dynamicParams = dynamicParams.substring(1);
                params += "&" + ParamsUtil.encode(dynamicParams);
            }
        }
        return params;
    }

    /**
     * 创建备忘录
     */
    private void createMemento(String params){
        String[] paramsArr = StringUtils.split(params, "&");
        String startTime = null ,endTime = null,isSrc = null, dataType = null,uCode = null;
        for (String param : paramsArr) {
            String name = param.split("=")[0];
            String value = param.split("=")[1];
            if ("isSrc".equals(name)) {
                isSrc = value;
                continue;
            }
            if ("dataType".equals(name)) {
                dataType = value;
                continue;
            }
            if ("startTime".equals(name)) {
                startTime =value;
                continue;
            }
            if ("endTime".equals(name)) {
                endTime =value;
                continue;
            }
            if ("uCode".equals(name)) {
                uCode =value;
                continue;
            }
        }

        ZzCityOriginator zzCityOriginator = new ZzCityOriginator(isSrc,dataType,startTime ,endTime,uCode,0);
        ZzCityMemento zzCityMemento = zzCityOriginator.createMemento();

        ZzCityCareTaker.newInstance().saveOrUpdate(HashUtil.hashCode(isSrc+dataType+startTime+endTime),zzCityMemento);
        log.debug("郑州市创建备忘录："+ isSrc+"|"+dataType+"|"+startTime+"|"+endTime+"|"+uCode);
    }
    /**
     * 更新备忘录
     */
    private void updateMemento(String params) {
        ZzCityCareTaker zzCityCareTaker = ZzCityCareTaker.newInstance();
        int key = HashUtil.getHashCodeByParams(params);
        ZzCityMemento zzCityMemento = zzCityCareTaker.get(key);
        zzCityCareTaker.update(key,zzCityMemento);
    }

    private void connect(String host,int port,String url,String params,ChannelInitializer channelInitializer){

        EventLoopGroup workerGroup = new NioEventLoopGroup();

        Bootstrap b = new Bootstrap();
        b.group(workerGroup);
        b.channel(NioSocketChannel.class);
        b.option(ChannelOption.SO_KEEPALIVE,true);
        b.option(ChannelOption.CONNECT_TIMEOUT_MILLIS,120);
        b.handler(channelInitializer);
        try {
            ChannelFuture channelFuture = b.connect(host,port).sync();
            java.net.URI reqUri = new URI(url);
            String uri = reqUri.getRawPath() + (StringUtils.isNotBlank(params) ? ("?" + params) : "");
            log.info("编码后请求地址和参数："+uri);
            DefaultFullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, uri);

            // 构建http请求
            request.headers().set(HttpHeaderNames.HOST, host);
            request.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
            request.headers().set(HttpHeaderNames.CONTENT_LENGTH, request.content().readableBytes());
            request.headers().set(HttpHeaderNames.CONTENT_TYPE,"application/json");

            // 发送http请求
            channelFuture.channel().writeAndFlush(request);
            channelFuture.channel().closeFuture().sync();

        }catch (Exception e){
            log.error(e);
            try {
                updateMemento(params);
            } catch (Exception e1) {
                log.error(e1);
            }
        }finally {
            workerGroup.shutdownGracefully();
        }
    }


    private ChannelInitializer getChannelInitializer(String host,int port,String url,String params){
        //获取通道初始器
        return  ChannelInitinalizerFactory.newInstance().getChannelInitializer(host, port, url, params);
    }
}
